package com.sample.transaction.atomikos.db1.config;

import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.mysql.cj.jdbc.MysqlXADataSource;
import com.sample.transaction.atomikos.common.config.CustomerProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.support.TransactionTemplate;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.sample.transaction.atomikos.db1",
	entityManagerFactoryRef = "firstEntityManagerFactory",
	transactionManagerRef="firstTransactionManager")
public class FirstDbConfig {

//    @Bean
//    @Primary //表示该bean为此类型的默认bean，在其他地方引用的时候用@Autowired即可按照类型注入，不受同类型多个对象影响
//    @ConfigurationProperties("db.first.datasource")
//    public DataSourceProperties firstDataSourceProperties() {
//        return new DataSourceProperties();
//    }
//
//    /**
//     * 数据源对象
//     * @return
//     */
//    @Bean
//    @Primary
//    public DataSource firstDataSource() {
//        return firstDataSourceProperties().initializeDataSourceBuilder().build();
//    }

    /**
     * 数据源配置对象
     * Primary 表示默认的对象，Autowire可注入，不是默认的得明确名称注入
     * @return
     */
    @Bean
    @Primary //表示该bean为此类型的默认bean，在其他地方引用的时候用@Autowired即可按照类型注入，不受同类型多个对象影响
    @ConfigurationProperties("db.first.datasource")
    public CustomerProperties firstDataSourceProperties() {
        return new CustomerProperties();
    }

    /**
     * 数据源对象
     * @return
     */
    @Bean
    @Primary
    public DataSource firstDataSource() {
        CustomerProperties dataSourceProperties = firstDataSourceProperties();
        final MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();

        mysqlXaDataSource.setUrl(dataSourceProperties.getUrl());
        mysqlXaDataSource.setPassword(dataSourceProperties.getPassword());
        mysqlXaDataSource.setUser(dataSourceProperties.getUsername());

        final AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXaDataSource);
        xaDataSource.setUniqueResourceName("firstDataSource");
        xaDataSource.setPoolSize(5);
        xaDataSource.setMinPoolSize(5);
        xaDataSource.setMaxPoolSize(5);
        xaDataSource.setMaxIdleTime(dataSourceProperties.getMaxIdle());
        xaDataSource.setMaxLifetime(600000);
        xaDataSource.setConcurrentConnectionValidation(true);
        xaDataSource.setTestQuery("select 1 from dual");
        log.info("初始化第一数据库成功");
        return xaDataSource;
    }

    /**
     * 实体管理对象
     * @param builder 由spring注入这个对象，首先根据type注入（多个就取声明@Primary的对象），否则根据name注入
     * @return
     */
    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory(
            EntityManagerFactoryBuilder builder) {
        return builder
                .dataSource(firstDataSource())
                .properties(getVendorProperties())
                .packages("com.sample.transaction.atomikos.db1.entity")
                .persistenceUnit("firstDb")
                .build();
    }

    /**
     * 事务管理对象
     * @return
     */
    @Bean(name = "firstTransactionManager")
    @Primary
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }

    @Bean
    @Primary
    public JdbcTemplate jdbcTemplate(){
        return new JdbcTemplate(firstDataSource());
    }

    @Bean
    @Primary
    public TransactionTemplate transactionTemplate(PlatformTransactionManager platformTransactionManager){
        return new TransactionTemplate(platformTransactionManager);
    }

    private Map<String, Object> getVendorProperties() {
        HashMap<String, Object> properties = new HashMap<>();
        // 注意这里要写为hibernate.hbm2ddl.auto 而不是hibernate.ddl-auto
        properties.put("hibernate.hbm2ddl.auto", "update");
        return properties;
    }

}
